package cn.afterturn.common.util;

import java.security.MessageDigest;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.slf4j.Logger;

/**
 * 加密工具类
 * @author JueYue
 * @date 2015年7月4日
 */
public final class EncryptionUtil {

    private static final Logger LOGGER = LemurLogger.getLogger();

    /**
     * encrypt data in ECB mode
     * @param data
     * @param key
     * @return
     */
    public static byte[] desEncrypt(byte[] data, byte[] key) {
        SecretKey sk = new SecretKeySpec(key, "DES");
        try {
            Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE, sk);
            byte[] enc = cipher.doFinal(data);
            return enc;
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }

        return null;
    }

    /**
     * decrypt data in ECB mode
     * @param data
     * @param key
     * @return
     */
    public static byte[] desDecrypt(byte[] data, byte[] key) {
        SecretKey sk = new SecretKeySpec(key, "DES");
        try {
            Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
            cipher.init(Cipher.DECRYPT_MODE, sk);
            byte[] enc = cipher.doFinal(data);
            return enc;
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }

        return null;
    }

    /**
     * encrypt data in ECB mode
     * @param data
     * @param key
     * @return
     */
    public static String desEncrypt(String data, String key) {
        byte[] bData, bKey, bOutput;
        String result;

        bData = String2Hex(data);
        bKey = String2Hex(key);
        bOutput = desEncrypt(bData, bKey);
        result = Hex2String(bOutput);

        return result;
    }

    /**
     * decrypt data in ECB mode
     * @param data
     * @param key
     * @return
     */
    public static String desDecrypt(String data, String key) {
        byte[] bData, bKey, bOutput;
        String result;

        bData = String2Hex(data);
        bKey = String2Hex(key);
        bOutput = desDecrypt(bData, bKey);
        result = Hex2String(bOutput);

        return result;
    }

    /**
     * encrypt data in ECB mode
     * @param data
     * @param key
     * @return
     */
    public static String tripledesEncrypt(String data, String key) {
        byte[] bData, bKey, bOutput;
        String result;

        bData = String2Hex(data);
        bKey = String2Hex(key);
        bOutput = tripleDesEncrypt(bData, bKey);
        result = Hex2String(bOutput);

        return result;
    }

    /**
     * decrypt data in ECB mode
     * @param data
     * @param key
     * @return
     */
    public static String tripledesDecrypt(String data, String key) {
        byte[] bData, bKey, bOutput;
        String result;

        bData = String2Hex(data);
        bKey = String2Hex(key);
        bOutput = tripleDesDecrypt(bData, bKey);
        result = Hex2String(bOutput);

        return result;
    }

    /**
     * encrypt data in ECB mode
     * @param data
     * @param key
     * @return
     */
    public static byte[] tripleDesEncrypt(byte[] data, byte[] key) {
        SecretKey sk = new SecretKeySpec(tripleDesGetKey(key), "DESede");
        try {
            Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE, sk);
            byte[] enc = cipher.doFinal(data);
            return enc;
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }

        return null;
    }

    /**
     * decrypt data in ECB mode
     * @param data
     * @param key
     * @return
     */
    public static byte[] tripleDesDecrypt(byte[] data, byte[] key) {
        SecretKey sk = new SecretKeySpec(tripleDesGetKey(key), "DESede");
        try {
            Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
            cipher.init(Cipher.DECRYPT_MODE, sk);
            byte[] enc = cipher.doFinal(data);
            return enc;
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }

        return null;
    }

    /**
     * get correct length key for triple DES operation
     * @param key
     * @return
     */
    private static byte[] tripleDesGetKey(byte[] key) {
        byte[] bKey = new byte[24];
        int i;

        if (key.length == 8) {
            for (i = 0; i < 8; i++) {
                bKey[i] = key[i];
                bKey[i + 8] = key[i];
                bKey[i + 16] = key[i];
            }
        } else if (key.length == 16) {
            for (i = 0; i < 8; i++) {
                bKey[i] = key[i];
                bKey[i + 8] = key[i + 8];
                bKey[i + 16] = key[i];
            }
        } else if (key.length == 24) {
            for (i = 0; i < 24; i++)
                bKey[i] = key[i];
        }

        return bKey;
    }

    /**
     * Convert Byte Array to Hex String
     * @param data
     * @return
     */
    public static String Hex2String(byte[] data) {
        String result = "";
        for (int i = 0; i < data.length; i++) {
            int tmp = (data[i] >> 4);
            result += Integer.toString((tmp & 0x0F), 16);
            tmp = (data[i] & 0x0F);
            result += Integer.toString((tmp & 0x0F), 16);
        }

        return result;
    }

    /**
     * Convert Hex String to byte array
     * @param data
     * @return
     */
    public static byte[] String2Hex(String data) {
        byte[] result;

        result = new byte[data.length() / 2];
        for (int i = 0; i < data.length(); i += 2)
            result[i / 2] = (byte) (Integer.parseInt(data.substring(i, i + 2), 16));

        return result;
    }

    /**
     * MD5 加密
     * @date 2014年2月19日
     * @param sign
     * @return
     */
    public static String getMD5(String sign) {
        return getmd5(sign).toUpperCase();
    }

    /**
     * MD5 加密
     * @date 2014年2月19日
     * @param sign
     * @return
     */
    public static String getmd5(String sign) {
        MessageDigest md;
        try {
            md = MessageDigest.getInstance("MD5");
            md.update(sign.getBytes());
            byte b[] = md.digest();
            int i;
            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0)
                    i += 256;
                if (i < 16)
                    buf.append("0");
                buf.append(Integer.toHexString(i));
            }
            return buf.toString();
        } catch (Exception e) {
            LOGGER.error("md5 cal is error ,param is {}", sign);
            LOGGER.error(e.getMessage(), e);
        }
        return null;
    }

}
